package com.toby.proxy.generator;

import com.toby.service.impl.UserServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import sun.misc.ProxyGenerator;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Modifier;
import java.nio.file.Files;

/**
 * @desc: 字节码生成器
 * @author: toby
 * @date: 2019/8/5 0:05
 */
public class ByteCodeGenerator {
    /**
     * 根据目标对象生成字节码(Jdk)
     * @param target
     * @param <T>
     * @return
     */
    public static <T> byte[] generatorByteCodeByJdkProxy(T target){
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
        byte [] codes = ProxyGenerator.generateProxyClass("Proxy$"+target.getClass().getName(), target.getClass().getInterfaces(),accessFlags);
        return codes;
    }

    /**
     * 根据目标对象生成字节码(Cglib)
     * @param target
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> byte[] generatorByteCodeByCglib(final T target) throws Exception {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invoke(target,objects));
        enhancer.create();
        byte [] codes = enhancer.getStrategy().generate(enhancer);
        return codes;
    }

    public static void main(String[] args) {
        /**
         * 测试jdk
         */
        try {
            byte [] codes = ByteCodeGenerator.generatorByteCodeByJdkProxy(new UserServiceImpl());
            File file = new File(System.getProperty("user.dir")+"/spring-aop/target/Proxy$UserServiceImpl.class");
            Files.write(file.toPath(),codes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        /**
         * 测试cglib
         */
        try {
            FileOutputStream out = new FileOutputStream(System.getProperty("user.dir")+"/spring-aop/target/Cglib$UserServiceImpl.class");
            out.write(ByteCodeGenerator.generatorByteCodeByCglib(new UserServiceImpl()));
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
